<script lang="ts">
export interface RegionPoint {
  lonDegree: string;
  lonMinute: string;
  lonSecond: string;
  lonDir: string;
  latDegree: string;
  latMinute: string;
  latSecond: string;
  latDir: string;
}

export const initPoint: RegionPoint = {
  lonDegree: '', lonMinute: '', lonSecond: '', lonDir: 'E',
  latDegree: '', latMinute: '', latSecond: '', latDir: 'N',
};

export const pointValidator = (point: RegionPoint, callback: any) => {
  const { lonDegree, lonMinute, lonSecond, latDegree, latMinute, latSecond } = point;
  const lonMin = Number(lonMinute || 0);
  const lonSec = Number(lonSecond || 0);
  const lon = Number(lonDegree) + lonMin / 60 + lonSec / 60 / 60;
  const latMin = Number(latMinute || 0);
  const latSec = Number(latSecond || 0);
  const lat = Number(latDegree) + latMin / 60 + latSec / 60 / 60;
  if (!lonDegree) {
    callback('请输入经度');
  } else if (Number.isNaN(lon)) {
    callback('请输入正确的经度');
  } else if (!latDegree) {
    callback('请输入纬度');
  } else if (Number.isNaN(lat)) {
    callback('请输入正确的纬度');
  } else if (lon < -180 || lon > 180) {
    callback('经度应该在-180至180之间');
  } else if (lat < -90 || lat > 90) {
    callback('纬度应该在-90至90之间');
  } else if (
    lonMin < 0 || lonMin >= 60 || latMin < 0 || latMin >= 60
    || lonSec < 0 || lonSec >= 60 || latSec < 0 || latSec >= 60
  ) {
    callback('分秒应当在0至60之间');
  } else {
    callback();
  }
};
</script>

<script setup lang="ts">
import { CirclePlus, Remove } from '@element-plus/icons-vue';
import { addRegion, changeRegionsFromId, RegionData } from 'common/src/apis';
import { getLatFromBreakDown, getLonFromBreakDown, latBreakDown, lonBreakDown } from 'common/src/utils/lnglat';
import {
  ElDialog, ElScrollbar,
  ElForm, ElFormItem, ElInput, ElDatePicker,
  ElIcon,
  ElMessage,
  FormInstance,
  FormRules,
  ElRadioGroup,
  ElRadio,
} from 'element-plus';
import dayjs from 'dayjs';
import { oneDay } from 'common/src/utils/time';
import { closeDrawPolygon, updateEditingPolygon } from 'common/src/utils/drawPolygon';
import { useTimeRangeStore, useWeatherStore } from '@/store';
import { updateExerciseSrc } from 'common/src/utils/layer';
import { regionOptions } from 'common/src/utils/special';
import { ActiveRegionInfo } from './index.vue';

interface Props {
  complete: () => void;
}

interface Emits {
}

interface RegionInfo {
  name: string;
  comment: string;
  /** 类型，2表示演习区 3表示养殖区 4表示浮标 5表示沉船 6表示井架 7表示海光缆 8表示未爆弹 9表示训练区 */
  type: number;
  timeRange: string[];
  points: RegionPoint[];
}

const today = dayjs(dayjs().format('YYYY/MM/DD')).valueOf();
const dateFormat = 'YYYY-MM-DD HH:mm';
const initTimeRange = [dayjs(today).format(dateFormat), dayjs(today + 30 * oneDay).format(dateFormat)];

const props = withDefaults(defineProps<Props>(), {});
const emits = defineEmits<Emits>();
const timeRangeStore = useTimeRangeStore();
const weatherStore = useWeatherStore();
const formRef = ref<FormInstance>();
const loading = ref(false);
const editId = ref(0);
const show = ref(false);
const regionInfo = reactive<RegionInfo>({
  name: '',
  comment: '',
  timeRange: [...initTimeRange],
  type: 2,
  points: [
    { ...initPoint },
    { ...initPoint },
    { ...initPoint },
  ],
});

const rules = reactive<FormRules>({
  type: [
    { required: true, message: '请选择区域类型', trigger: ['blur'] },
  ],
  name: [
    { required: true, message: '请输入区域名称', trigger: ['blur'] },
    { pattern: /\S+/, message: '请输入区域名称', trigger: ['blur', 'change'] },
    { max: 30, message: '最长30位字符', trigger: ['change'] },
  ],
  comment: [
    { max: 200, message: '最长200位字符', trigger: ['change'] },
  ],
});

const updateEditedRegion = () => {
  const points = regionInfo.points.filter(point => {
    const { lonDegree, lonMinute, lonSecond, latDegree, latMinute, latSecond } = point;
    return ([lonDegree, lonMinute, lonSecond].join('') !== '') && ([latDegree, latMinute, latSecond].join('') !== '');
  }).map(point => {
    const { lonDegree, lonMinute, lonSecond, lonDir, latDegree, latMinute, latSecond, latDir } = point;
    const lon = getLonFromBreakDown(lonDir, lonDegree, lonMinute, lonSecond);
    const lat = getLatFromBreakDown(latDir, latDegree, latMinute, latSecond);
    return [lon, lat];
  }).filter(point => !Number.isNaN(point[0]) && !Number.isNaN(point[1])) as [number, number][];
  updateEditingPolygon(weatherStore.map as any, points);
};

const handleCancelEdit = () => {
  show.value = false;
  closeDrawPolygon();
  props.complete();
};

const handleSaveEdit = async () => {
  const valid = await formRef.value?.validate();
  if (!valid) {
    return;
  }
  if (regionInfo.points.length > 30) {
    ElMessage({
      type: 'warning',
      message: '点位最多设置为30个',
    });
    return;
  } else if (regionInfo.points.length < 3) {
    ElMessage({
      type: 'warning',
      message: '请至少添加3个点位',
    });
    return;
  }
  loading.value = true;
  try {
    const points: [number, number][] = regionInfo.points.map(point => {
      const { lonDegree, lonMinute, lonSecond, lonDir, latDegree, latMinute, latSecond, latDir } = point;
      const lon = getLonFromBreakDown(lonDir, lonDegree, lonMinute, lonSecond);
      const lat = getLatFromBreakDown(latDir, latDegree, latMinute, latSecond);
      return [lon, lat];
    });
    const { name, type, timeRange, comment }  = regionInfo;
    const data: RegionData = {
      name: name.trim(),
      type,
      comment: comment || '',
      source: 'custom',
      bound: {
        type: 'Polygon',
        areaType: 3,
        coordinates: [...points, points[0]],
      },
    };
    if (type === 2) {
      data.beginTs = new Date(timeRange[0]).valueOf();
      data.dueTs = new Date(timeRange[1]).valueOf();
    }
    if (editId.value === 0) {
      await addRegion(data);
      ElMessage({
        message: '添加成功！',
        type: 'success',
      });
    } else {
      await changeRegionsFromId(editId.value, data);
      ElMessage({
        message: '修改成功！',
        type: 'success',
      });
    }
    closeDrawPolygon();
    updateExerciseSrc(weatherStore.map as any, timeRangeStore.start, timeRangeStore.end);
    show.value = false;
    loading.value = false;
    props.complete();
  } catch(err) {
    loading.value = false;
    console.log(err);
    ElMessage({
      message: '操作失败！',
      type: 'warning',
    });
  }
};

const handleReomvePoint = (idx: number) => {
  regionInfo.points.splice(idx, 1);
  updateEditedRegion();
};

const handleAddPoint = () => {
  regionInfo.points.push({...initPoint});
};

const editRegion = (region: Partial<ActiveRegionInfo>) => {
  show.value = true;
  formRef.value?.clearValidate();
  const { points, id, name, comment, begin, end, type } = region;
  if (points) {
    regionInfo.points = points.map(point => {
      const [lonDegree, lonMinute, lonSecond, lonDir] = lonBreakDown(point[0]);
      const [latDegree, latMinute, latSecond, latDir] = latBreakDown(point[1]);
      return {
        lonDir, latDir,
        latDegree: String(latDegree), lonDegree: String(lonDegree),
        latMinute: String(latMinute), lonMinute: String(lonMinute),
        latSecond: String(latSecond), lonSecond: String(lonSecond),
      };
    });
  } else {
    regionInfo.points = [
      { ...initPoint },
      { ...initPoint },
      { ...initPoint },
    ];
  }
  if (id !== undefined) {
    editId.value = id;
    updateEditedRegion();
  } else {
    editId.value = 0;
  }
  Object.assign(regionInfo, {
    name: name || '',
    comment: comment || '',
    type: type || 2,
    timeRange: begin && end ? [dayjs(begin).format(dateFormat), dayjs(end).format(dateFormat)] : [...initTimeRange],
  });
};

defineExpose({ editRegion });
</script>

<template>
  <ElDialog
    :class="['custom-dialog', 'region-edit-dialog']"
    v-model="show"
    :title="editId ? '编辑区域' : '创建区域'"
    width="730px"
    :modal="false"
    modal-class="pointer-none-dialog-modal"
    :close-on-click-modal="false"
    @close="() => handleCancelEdit()"
  >
    <ElScrollbar max-height="50vh">
      <ElForm ref="formRef" :model="regionInfo" :rules="rules" style="padding-right: 16px;" label-position="left">
        <ElFormItem prop="type" label-width="100px" label="区域类型">
          <ElRadioGroup v-model="regionInfo.type">
            <ElRadio
              v-for="region in regionOptions"
              :key="region.value"
              :value="region.value"
            >{{ region.label }}</ElRadio>
          </ElRadioGroup>
        </ElFormItem>
        <ElFormItem>
          <ElFormItem prop="name" label="名称" label-width="60px" style="flex: 1;">
            <ElInput placeholder="请输入" v-model="regionInfo.name" />
          </ElFormItem>
          <ElFormItem
            v-if="regionInfo.type === 2"
            prop="timeRange"
            label="有效期"
            :rules="[{ required: true, message: '请选择演习区有效期', trigger: ['blur'] }]"
            style="margin-left: 12px; flex: 1;"
          >
            <ElDatePicker
              placeholder="请输入"
              v-model="regionInfo.timeRange"
              type="datetimerange"
              :format="dateFormat"
              :value-format="dateFormat"
              start-placeholder="开始时间"
              end-placeholder="结束时间"
              :clearable="false"
            />
          </ElFormItem>
        </ElFormItem>
        <ElFormItem prop="comment" label-width="60px" label="备注">
          <ElInput placeholder="请输入" v-model="regionInfo.comment" type="textarea" :rows="3" resize="none" />
        </ElFormItem>
        <ElFormItem
          v-for="(point, idx) in regionInfo.points"
          :prop="`point.${idx}`"
          class="region-point-item"
          :rules="[
            { required: true, validator: (_rule: any, _value: any, callback: any) => pointValidator(point, callback) },
          ]"
        >
          <span class="point-index">{{ idx + 1 }}</span>
          <ElInput v-model.trim="point.latDegree" style="width: 90px; margin-right: 5px;" placeholder="纬度" @blur="() => updateEditedRegion()">
            <template #suffix>°</template>
          </ElInput>
          <ElInput v-model.trim="point.latMinute" style="width: 90px; margin-right: 5px;" placeholder="00" @blur="() => updateEditedRegion()">
            <template #suffix>'</template>
          </ElInput>
          <ElInput v-model.trim="point.latSecond" style="width: 90px; margin-right: 5px;" placeholder="00" @blur="() => updateEditedRegion()">
            <template #suffix>''</template>
          </ElInput>
          <span
            class="point-direction"
            @click="() => {
              point.latDir = point.latDir === 'N' ? 'S' : 'N';
              updateEditedRegion();
            }"
          >{{ point.latDir }}</span>
          <ElInput v-model.trim="point.lonDegree" style="width: 90px; margin-right: 5px;" placeholder="经度" @blur="() => updateEditedRegion()">
            <template #suffix>°</template>
          </ElInput>
          <ElInput v-model.trim="point.lonMinute" style="width: 90px; margin-right: 5px;" placeholder="00" @blur="() => updateEditedRegion()">
            <template #suffix>'</template>
          </ElInput>
          <ElInput v-model.trim="point.lonSecond" style="width: 90px; margin-right: 5px;" placeholder="00" @blur="() => updateEditedRegion()">
            <template #suffix>''</template>
          </ElInput>
          <span
            class="point-direction"
            @click="() => {
              point.lonDir = point.lonDir === 'E' ? 'W' : 'E';
              updateEditedRegion();
            }"
          >{{ point.lonDir }}</span>
          <ElIcon v-if="idx === regionInfo.points.length - 1" @click="() => handleAddPoint()">
            <CirclePlus />
          </ElIcon>
          <ElIcon v-show="regionInfo.points.length > 3" @click="() => handleReomvePoint(idx)">
            <Remove />
          </ElIcon>
        </ElFormItem>
      </ElForm>
    </ElScrollbar>
    <div class="dialog-footer">
      <ElButton @click="() => handleCancelEdit()">取消</ElButton>
      <ElButton
        :loading="loading"
        type="primary"
        @click="() => handleSaveEdit()"
      >确定</ElButton>
    </div>
  </ElDialog>
</template>

<style lang="less">
.custom-dialog.region-edit-dialog.el-dialog {
  padding-right: 0;
  border: none;
  --el-dialog-margin-top: 50px;
  .el-dialog__body {
    padding: 0 0;
  }
  .dialog-footer {
    padding: 6px 16px 0 0;
    justify-content: flex-end;
    .el-button {
      flex: 0;
    }
    .el-button + .el-button {
      margin-left: 20px;
    }
  }
}

.region-point-item {
  .point-index {
    display: inline-block;
    height: 18px;
    width: 18px;
    border-radius: 50%;
    line-height: 16px;
    text-align: center;
    border: 1px solid #ccc;
    margin-right: 8px;
    color: #ccc;
  }
  .point-direction {
    display: inline-block;
    width: 22px;
    color: #ccc;
    height: 32px;
    line-height: 30px;
    text-align: center;
    background-color: rgba(0, 0, 0, 0.24);
    cursor: pointer;
    &:not(:last-child) {
      margin-right: 6px;
    }
  }
  .el-input__suffix-inner {
    position: relative;
    top: -4px;
  }
  .el-input__wrapper {
    padding-right: 6px;
  }
  .el-icon {
    font-size: 20px;
    color: #ccc;
    cursor: pointer;
    &:not(:last-child) {
      margin-right: 6px;
    }
  }
}
</style>
